package main

import (
	"bytes"
	"context"
	"encoding/binary"
	"io"
	"os"
	"os/signal"
	"syscall"

	"gitee.com/simonxie979/skymeta/logutil"
	"gitee.com/simonxie979/skymeta/network"
	"gitee.com/simonxie979/skymeta/uuid"
)

type Server struct {
	ctx  context.Context
	comm *network.Communicator[string]
	log  *logutil.Logger
}

func NewServer(ctx context.Context) *Server {
	s := new(Server)
	s.ctx = ctx
	s.log = logutil.NewLogger(ctx, ".", "server", "text")
	s.log.SetLevel("debug")
	s.comm = network.NewCommunicator[string](ctx, s, s.log)

	return s
}

func (s *Server) OnConnect(sessionID uint64, addr string) {
	s.log.Infof("Server", "new connection %v %v", sessionID, addr)
}

func (s *Server) OnDisconnect(sessionID uint64, err error) {
	s.log.Infof("Server", "%v disconnect with error: %v", sessionID, err)
}

func (s *Server) OnMessage(sessionID uint64, data string) {
	s.log.Infof("Server", "recive: %s", data)

	s.comm.SendMsg(sessionID, data)
}

func (s *Server) Pack(payload string, buf *bytes.Buffer) {
	headerBuf := headerBufPool.Get().(*[]byte)
	defer headerBufPool.Put(headerBuf)

	binary.BigEndian.PutUint32(*headerBuf, uint32(len(payload)))
	buf.Write(*headerBuf)
	buf.WriteString(payload)
}

func (s *Server) Unpack(reader io.Reader) (payload string, err error) {
	headerBuf := headerBufPool.Get().(*[]byte)
	defer headerBufPool.Put(headerBuf)

	_, err = io.ReadAtLeast(reader, *headerBuf, headerSize)
	if err != nil {
		return
	}

	length := binary.BigEndian.Uint32(*headerBuf)
	data := make([]byte, length)

	_, err = io.ReadFull(reader, data)

	payload = string(data)
	return
}

func RunServer() {
	uuid.Init(0)

	ctx, cancel := context.WithCancel(context.Background())

	server := NewServer(ctx)
	defer server.log.Wait()
	defer server.comm.Close()
	defer cancel()

	server.log.Infof("Server", "开始")
	defer server.log.Infof("Server", "结束")

	if err := server.comm.ListenTCP("tcp", ":8888"); err != nil {
		server.log.Panicf("Server", "监听错误：%v", err)
		return
	}

	sigChan := make(chan os.Signal, 1)
	signal.Notify(sigChan, syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGINT)
	sig := <-sigChan
	server.log.Infof("Server", "收到 %v 信号", sig)
}
